#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <nettle/hmac.h>
#include <nettle/sm3.h>

#include "hash.h"

static int init_ctx(void **ctx, uint8_t *key, uint32_t klen, uint16_t alg)
{
	struct sm3_ctx *sm3_ctx = NULL;

	sm3_ctx = malloc(sizeof(struct sm3_ctx));
	if (NULL == sm3_ctx)
		return -1;

	sm3_init(sm3_ctx);

	*ctx = sm3_ctx;

	return 0;
}

static void free_ctx(void *ctx)
{
	free(ctx);
	return;
}

static int update(void *ctx, uint8_t *data, uint32_t len)
{
	sm3_update(ctx, len, (const uint8_t *)data);
	return 0;
}

static int finish(void *ctx, uint8_t *dgst)
{
	sm3_digest(ctx, 32, dgst);

	return 0;
}

static int digest(uint8_t *data, uint32_t len, uint8_t *key, uint32_t klen,
		  uint8_t *dgst, uint16_t alg)
{
	struct sm3_ctx ctx;

	sm3_init(&ctx);

	sm3_update(&ctx, len, data);

	sm3_digest(&ctx, 32, dgst);

	return 0;
}

static struct abcrypto_auth hash = {
	.init_ctx = init_ctx,
	.free_ctx = free_ctx,
	.update = update,
	.finish = finish,
	.digest = digest,
};

struct abcrypto_auth *nettle_hash(void)
{
	return &hash;
}

static int hmac_init_ctx(void **ctx, uint8_t *key, uint32_t klen, uint16_t alg)
{
	struct hmac_sm3_ctx *hmac_ctx;

	hmac_ctx = malloc(sizeof(struct hmac_sm3_ctx));
	if (NULL == hmac_ctx)
		return -1;

	hmac_sm3_set_key(hmac_ctx, klen, key);

	*ctx = hmac_ctx;

	return 0;
}

static void hmac_free_ctx(void *ctx)
{
	free(ctx);
	return;
}

static int hmac_update_n(void *ctx, uint8_t *data, uint32_t len)
{
	hmac_sm3_update(ctx, len, data);

	return 0;
}

static int hmac_finish(void *ctx, uint8_t *dgst)
{
	hmac_sm3_digest(ctx, 32, dgst);
	return 0;
}

static int hmac_digest_n(uint8_t *data, uint32_t len, uint8_t *key,
			 uint32_t klen, uint8_t *dgst, uint16_t alg)
{
	struct hmac_sm3_ctx ctx;

	hmac_sm3_set_key(&ctx, klen, key);

	hmac_sm3_update(&ctx, len, data);

	hmac_sm3_digest(&ctx, 32, dgst);

	return 0;
}

static struct abcrypto_auth hmac = {
	.init_ctx = hmac_init_ctx,
	.free_ctx = hmac_free_ctx,
	.update = hmac_update_n,
	.finish = hmac_finish,
	.digest = hmac_digest_n,
};

struct abcrypto_auth *nettle_hmac(void)
{
	return &hmac;
}
